﻿using CommonDevelop;
using CommonDevelop.Operator;
using CommonDevelop.Scene;
using CommonEngine;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;

namespace WebAdmin.Handler
{
    /// <summary>
    /// 基础控制器
    /// </summary>
    [Authorize(Policy = AuthPolicy.CHECK)]
    public class BaseController : Controller
    {
        /// <summary>
        /// 当前登录用户信息
        /// </summary>
        public UserInfo Current { set; get; }
        /// <summary>
        /// 当前菜单ID
        /// </summary>
        public string moduleId { get; set; }
        /// <summary>
        /// 当前Url
        /// </summary>
        public string currentUrl { get; set; }

        private List<SysMenu> MenuData { get; set; }
        /// <summary>
        /// 在调用操作方法前调用
        /// </summary>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            this.Current = OperatorProvider.Provider.Current();
            if (this.Current == null)
            {
                base.OnActionExecuting(filterContext);
                return;
            }

            var areaName = filterContext.RouteData.Values["area"] + "/";                //获取当前区域
            var controllerName = filterContext.RouteData.Values["controller"] + "/";    //获取控制器
            var action = filterContext.RouteData.Values["Action"];                      //获取当前Action
            this.currentUrl = "/" + areaName + controllerName + action;                 //拼接构造完整url

            var flg = BizPage.IsAjaxRequest(this.ControllerContext.HttpContext.Request);
            if (!flg)
            {
                //判断访问地址
                this.MenuData = GlobalData.GetMenu(this.Current);
                var M = MenuData.FirstOrDefault(a => a.Module_Action.ToLower().Equals(this.currentUrl.ToLower()));
                if (M != null)
                    this.moduleId = M.Module_Id;
            }
            base.OnActionExecuting(filterContext);
        }
        /// <summary>
        /// 在调用操作方法后调用
        /// </summary>
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (this.Current == null)
            {
                base.OnActionExecuted(filterContext);
                return;
            }

            var rootUrl = new StringBuilder()
                   .Append(Request.Scheme)
                   .Append("://").Append(Request.Host)
                   .Append(Request.PathBase)
                   .ToString();

            ViewBag.rootUrl = rootUrl;
            var flg = BizPage.IsAjaxRequest(this.ControllerContext.HttpContext.Request);
            if (!flg && !this.Current.UserId.IsEmpty())
            {
                ViewBag.UserNo = this.Current.UserId;
                ViewBag.UserName = this.Current.NickName;
                ViewBag.UserDescribe = this.Current.FullName;
                ViewBag.UserLogoUrl = this.Current.HeadIcon;
                ViewBag.MenuData = MenuBox.GetMenuData(this.MenuData, this.moduleId);
                ViewBag.SSOToken = this.Current.Token;
                ViewBag.JwtToken = this.Current.JWT_Token;
            }

            base.OnActionExecuted(filterContext);
        }

        #region 请求响应--可以继续扩展

        /// <summary>
        /// 返回Json数据，这种输出方式，针对jstree按Url取数据
        /// </summary>
        protected virtual ActionResult ToJsonContent(object Data)
        {
            string json = JsonHelper.SerializeObject(Data);
            return Content(json, "application/json;charset=utf-8", Encoding.UTF8);
        }
        /// <summary>
        /// 返回Json数据
        /// </summary>
        protected virtual ActionResult ToJsonContentNoRN(object Data)
        {
            string json = JsonHelper.SerializeObjectNoRN(Data);
            return Content(json, "application/json;charset=utf-8", Encoding.UTF8);
        }
        /// <summary>
        /// 返回Json数据
        /// </summary>
        protected virtual ActionResult ToJsonResult(object data)
        {
            return Json(data);
        }
        /// <summary>
        /// 返回文本信息
        /// </summary>
        protected virtual ActionResult Success(string info)
        {
            return Content(new ResponseParameter { code = ResponseCode.success, info = info }.ToJson());
        }
        /// <summary>
        /// 返回Success
        /// </summary>
        protected virtual ActionResult Success(string info, object data)
        {
            if (data == null)
                data = new object { };

            return Content(new ResponseParameter { code = ResponseCode.success, info = info, data = data }.ToJson());
        }
        /// <summary>
        /// 返回SuccessUrl
        /// </summary>
        protected virtual ActionResult SuccessUrl(string info, string url)
        {
            return Content(new ResponseParameter { code = ResponseCode.success, info = info, url = url }.ToJson());
        }
        /// <summary>
        /// 返回SuccessJson
        /// </summary>
        protected virtual ActionResult SuccessJson(object jsonData, string info = null)
        {
            return Json(new ResponseParameter { code = ResponseCode.success, data = jsonData, info = info });
        }
        /// <summary>
        /// 带操作日志
        /// </summary>
        protected virtual ActionResult SuccessLog(string info, string title, LogType type, string keyValue, string content)
        {
            LogModel operateLogModel = new LogModel();
            operateLogModel.LogTitle = title;
            operateLogModel.LogType = type;
            operateLogModel.LogModule = this.currentUrl;
            operateLogModel.ObjectId = keyValue;
            operateLogModel.ContentJson = content;
            operateLogModel.ResultInfo = info;

            OperatorProvider.Provider.WriteOperateLog(operateLogModel);
            return Content(new ResponseParameter { code = ResponseCode.success, info = info, data = new object { } }.ToJson());
        }
        /// <summary>
        /// 返回失败消息
        /// </summary>
        protected virtual ActionResult Fail(string info)
        {
            return Content(new ResponseParameter { code = ResponseCode.fail, info = info }.ToJson());
        }
        /// <summary>
        /// 返回失败消息
        /// </summary>
        protected virtual ActionResult Fail(string info, object data)
        {
            return Content(new ResponseParameter { code = ResponseCode.fail, info = info, data = data }.ToJson());
        }

        #endregion

        /// <summary>
        /// DownloadBigFile用于下载大文件，循环读取大文件的内容到服务器内存，然后发送给客户端浏览器
        /// </summary>
        public void DownloadBigFile(string fileName, string filePath)
        {
            //要下载的文件地址，这个文件会被分成片段，通过循环逐步读取到ASP.NET Core中，然后发送给客户端浏览器
            var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();
            if (syncIOFeature != null)  //使用Enablebuffering多次读取，需要AllowSynchronousIO
                syncIOFeature.AllowSynchronousIO = true;

            //这就是ASP.NET Core循环读取下载文件的缓存大小，这里我们设置为了1024字节，也就是说ASP.NET Core每次会从下载文件中读取1024字节的内容到服务器内存中，
            //然后发送到客户端浏览器，这样避免了一次将整个下载文件都加载到服务器内存中，导致服务器崩溃
            int bufferSize = 1024;
            Response.ContentType = "application/octet-stream";

            //在Response的Header中设置下载文件的文件名，这样客户端浏览器才能正确显示下载的文件名，注意这里要用HttpUtility.UrlEncode编码文件名，否则有些浏览器可能会显示乱码文件名
            var contentDisposition = "attachment;" + "filename=" + HttpUtility.UrlEncode(fileName);
            Response.Headers.Add("Content-Disposition", new string[] { contentDisposition });

            //使用FileStream开始循环读取要下载文件的内容
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                using (Response.Body)//调用Response.Body.Dispose()并不会关闭客户端浏览器到ASP.NET Core服务器的连接，之后还可以继续往Response.Body中写入数据
                {
                    long contentLength = fs.Length;//获取下载文件的大小
                    Response.ContentLength = contentLength;//在Response的Header中设置下载文件的大小，这样客户端浏览器才能正确显示下载的进度

                    byte[] buffer;
                    long hasRead = 0;//变量hasRead用于记录已经发送了多少字节的数据到客户端浏览器

                    //如果hasRead小于contentLength，说明下载文件还没读取完毕，继续循环读取下载文件的内容，并发送到客户端浏览器
                    while (hasRead < contentLength)
                    {
                        //HttpContext.RequestAborted.IsCancellationRequested可用于检测客户端浏览器和ASP.NET Core服务器之间的连接状态，如果HttpContext.RequestAborted.IsCancellationRequested返回true，说明客户端浏览器中断了连接
                        if (HttpContext.RequestAborted.IsCancellationRequested)
                        {
                            //如果客户端浏览器中断了到ASP.NET Core服务器的连接，这里应该立刻break，取消下载文件的读取和发送，避免服务器耗费资源
                            break;
                        }

                        buffer = new byte[bufferSize];
                        int currentRead = fs.Read(buffer, 0, bufferSize);//从下载文件中读取bufferSize(1024字节)大小的内容到服务器内存中
                        Response.Body.Write(buffer, 0, currentRead);//发送读取的内容数据到客户端浏览器
                        Response.Body.Flush();//注意每次Write后，要及时调用Flush方法，及时释放服务器内存空间

                        hasRead += currentRead;//更新已经发送到客户端浏览器的字节数
                    }
                }
            }
        }
        /// <summary>
        /// 下载文件并是否删除
        /// </summary>
        public bool DownloadFile(string fileName, string filePath, bool HasDeleteFile = false)
        {
            bool result = false;
            try
            {
                this.DownloadBigFile(fileName, filePath);
                result = true;
            }
            catch
            {
                result = false;
            }
            finally
            {
                if (result && HasDeleteFile)
                    if (System.IO.File.Exists(filePath))
                        System.IO.File.Delete(filePath);
            }
            return result;
        }
    }
}
